package org.mm.proxycache;

import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.concurrent.Executors;

import org.apache.mina.common.DefaultIoFilterChainBuilder;
import org.apache.mina.common.IoBuffer;
import org.apache.mina.common.SimpleBufferAllocator;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.executor.ExecutorFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import org.mm.proxycache.cache.CacheFilter;
import org.mm.proxycache.config.Config;
import org.mm.proxycache.config.ConfigReader;
import org.mm.proxycache.http.codec.HttpCodecFactory;
import org.mm.proxycache.util.SessionDataStructureFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Stage;

public class Main
{
    private static int IDLE_TIMEOUT = 300;
    
    private static Logger log = LoggerFactory.getLogger( Main.class );
    
    public static void main( String[] args ) throws Exception
    {
        Injector injector = Guice.createInjector( Stage.PRODUCTION );
        injector.getInstance( ConfigReader.class );
        Config config = injector.getInstance( Config.class );
        
        Runtime.getRuntime().addShutdownHook( injector.getInstance( ShutdownHandler.class ) );
        
        IoBuffer.setUseDirectBuffer( false );
        IoBuffer.setAllocator( new SimpleBufferAllocator() );
        
        ProxyClientHandler handler = injector.getInstance( ProxyClientHandler.class );
        
        NioSocketAcceptor acceptor = new NioSocketAcceptor();
        
        acceptor.setReuseAddress( true );
        acceptor.getSessionConfig().setKeepAlive( true );
        acceptor.setReaderIdleTime( IDLE_TIMEOUT );
        acceptor.setSessionDataStructureFactory( new SessionDataStructureFactory() );
        
        DefaultIoFilterChainBuilder filterChain = acceptor.getFilterChain();
        filterChain.addFirst( "threadPool", new ExecutorFilter( Executors.newCachedThreadPool() ) );
        // filterChain.addLast( "https-bypasser", injector
        // .getInstance( ProxyClientHttpsFilterBypass.class ) );
        filterChain.addLast( "http-codec", new ProtocolCodecFilter( new HttpCodecFactory() ) );
        // filterChain.addLast( "https-handler", injector.getInstance(
        // ProxyClientHttpsFilter.class ) );
        
        if ( config.cacheEnabled )
        {
            log.info( "Cache is enabled" );
            filterChain.addLast( "cache", injector.getInstance( CacheFilter.class ) );
        }
        
        acceptor.setHandler( handler );
        acceptor.setBacklog( 200 );
        
        SocketAddress address = new InetSocketAddress( config.proxyAddress, config.proxyPort );
        acceptor.bind( address );
        
        log.info( "Started server at {}", address );
    }
}
